const db = require('../../models/index');
const logger = require('../../utils/logger-util');
const jwt = require('jsonwebtoken');
const { Op } = require("sequelize");
const { SEND_EMAIL_TYPE } = require('../../constants/system/email-constants');
const redis = require('../../redis/index');
const DAO = require('../../dao/sql-option-dao');
const { toolsUtil }  = require('../../utils/tools-util');
const { MENUS_TYPE } = require('../../constants/system/user-constants');
const Users = db.users;
const Roles = db.roles;
const Menus = db.menus;
const usersRoles = db.usersRoles;
const Article = db.article;
const Comments = db.comments;
const Danmu = db.danmu;
const { aes,md5 } = require('../../utils/crypto-util');

const { baseURL } = require('../../config/multer-config');

// 用户-角色 多对多关系
Users.belongsToMany(Roles, {
    through: {
        model: usersRoles
    },
    foreignKey: 'userId'
});

Roles.belongsToMany(Users, {
    through: {
        model: usersRoles
    },
    foreignKey: 'roleIds'
});

// 用户-弹幕 一对多关系
Users.hasMany(Danmu, {
    foreignKey: 'userId',
    sourceKey: 'id'
});
Danmu.belongsTo(Users, {
    foreignKey: 'userId',
    sourceKey: 'id'
});

/**
 *  注册-普通用户
 * 
*/
exports.register = async (req, res) => {
    try {
        const userInfo = req.body;
        // 验证码比对
        const resRedis = await redis.getValue(`/${SEND_EMAIL_TYPE.REGISTER.value}-${userInfo.eMail}-emailCode`);
        if(!resRedis) return res.sendResultAto(null, 605, '验证码错误或已过期');
        const resCode = JSON.parse(resRedis);
        if(userInfo.verificationCode !== resCode.emailCode) return res.sendResultAto(null, 605, '验证码错误');
        // 插入前先查询是否有相同userId和email
        const resUser = await Users.findOne({
            where: { 
                [Op.or]:[
                    { user_id:userInfo.userId },
                    { eMail:userInfo.eMail }
                ]
            }
        });
        if(resUser && resUser.id) return res.sendResultAto(null, 605, '当前用户已存在');
        let roles = await Roles.findAll({ where:{ id: userInfo.roles} });
        // 默认昵称
        let code = Math.random().toString(16).slice(2, 8).toUpperCase();
        userInfo.nickname = '用户'+code;
        // 默认头像
        userInfo.avatar = 'images/web-site/website-avatar.jpg';
        // 创建用户
        let newUser = await Users.create(userInfo);
        // 更新关联表
        await newUser.setRoles(roles);
        logger.info(`${req.method} ${req.baseUrl + req.path} *** 参数：${JSON.stringify(userInfo)}; 响应：${JSON.stringify(newUser)}`);
        resRedis && redis.deleteValue(`/${SEND_EMAIL_TYPE.REGISTER.value}-${userInfo.eMail}-emailCode`);
        res.sendResultAto(newUser, 200, '创建成功');
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

// 创建用户
exports.create = async (req, res) => {
    try {
        const userInfo = req.body;
        // 插入前先查询是否有相同userId和email
        const resUser = await Users.findOne({
            where: { 
                // [Op.or]:[
                //     { user_id:userInfo.userId },
                //     { eMail:userInfo.eMail }
                // ]
                userId: userInfo.userId
            }
        });
        if(resUser && resUser.id) return res.sendResultAto(null, 605, '当前用户已存在');
        let roles = await Roles.findAll({ where:{ id: userInfo.roles} });
        // 创建用户
        let newUser = await Users.create(userInfo);
        // 更新关联表
        await newUser.setRoles(roles);
        logger.info(`${req.method} ${req.baseUrl + req.path} *** 参数：${JSON.stringify(userInfo)}; 响应：${JSON.stringify(newUser)}`);
        res.sendResultAto(newUser, 200, '创建成功');
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

/**
 *  重置用户密码
 * 
*/
exports.resetPassword = async (req, res) => {
    try {
        const userInfo = req.body;
        let resRedis = null
        if(!userInfo.id) { // 区分是忘记密码还是重置密码
            // 验证码比对
            resRedis = await redis.getValue(`/${SEND_EMAIL_TYPE.UPDATE_PASSWORD.value}-${userInfo.eMail}-emailCode`);
            if(!resRedis) return res.sendResultAto(null, 605, '验证码错误或已过期');
            const resCode = JSON.parse(resRedis);
            if(userInfo.verificationCode !== resCode.emailCode) return res.sendResultAto(null, 605, '验证码错误');
        };
        const resUpdate = await Users.update({password:userInfo.password}, {
            where:{
                [Op.or]: [
                    {
                        id: {
                            [Op.ne]:null,
                            [Op.eq]:userInfo.id,
                        },
                        phoneNumber: {
                            [Op.ne]:null,
                            [Op.eq]:userInfo.phone_number,
                        }
                    }
                ]
            }
        });
        resRedis && redis.deleteValue(`/${SEND_EMAIL_TYPE.UPDATE_PASSWORD.value}-${userInfo.eMail}-emailCode`);
        if(!resUpdate) return res.status(500).sendResultAto(null, 605, '重置密码失败');
        res.status(200).sendResultAto(null, 200, '重置密码成功');
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

// 重置邮箱
exports.resetEmail = async (req, res) => {
    try {
        const userInfo = req.body;
        // 验证码
        const resRedis = await redis.getValue(`/${SEND_EMAIL_TYPE.UPDATE_EMAIL.value}-${userInfo.eMail}-emailCode`);
        if(!resRedis) return res.sendResultAto(null, 605, '验证码错误或已过期');
        const resCode = JSON.parse(resRedis);
        if(userInfo.verificationCode !== resCode.emailCode) return res.sendResultAto(null, 605, '验证码错误');
        // 密码
        let findUser = await Users.findByPk(userInfo.id);
        if(findUser && findUser.password !== md5(userInfo.password)) return res.sendResultAto(null, 605, '密码错误');
        // 是否已有邮箱
        const resUser = await Users.findOne({ where: { eMail: userInfo.eMail}});
        if(resUser && resUser.id !== userInfo.id) return res.sendResultAto(null, 605, '当前邮箱已存在');
        // 修改邮箱
        const resUpdate = await Users.update({eMail:userInfo.eMail},{ where: { id:userInfo.id } });
        redis.deleteValue(`/${SEND_EMAIL_TYPE.UPDATE_EMAIL.value}-${userInfo.eMail}-emailCode`);
        if(!resUpdate) return res.status(500).sendResultAto(null, 605, '修改邮箱失败');
        res.status(200).sendResultAto(null, 200, '修改邮箱成功');
    } catch (error) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    }
}

// 根据id 更新用户信息
exports.update = async (req, res) => {
    try {
        const userInfo = req.body;
        const resUser = await Users.findOne({where: { userId: userInfo.userId}});
        // 用户名不能重复
        if(resUser && resUser.id !== userInfo.id) return res.sendResultAto(null, 605, '当前用户名已存在');
        let roles = await Roles.findAll({ where:{ id: userInfo.roles} });
        Users.findByPk(userInfo.id).then(user => {
            user.update(userInfo);
            user.setRoles(roles);
            res.sendResultAto(null, 200, '修改成功');
        });
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

// 获取所有用户信息
exports.findAll = (req, res) => {
    try {
        const userInfo = req.body;
        userInfo.raw = false; //是否开启原生查询
        userInfo.include = [ // 执行预先加载
            {
                model: Roles
            }
        ];
        DAO.list(Users, userInfo, list => {
            // console.log(list)
            res.sendResult(list);
        })
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    }
}

// 根据id 获取用户信息
exports.findOne = async (req, res) => {
    try {
        const userInfo = req.body;
        if(userInfo.params.type === 'token') {
            let token =  req.headers.authorization;
            token = token.replace('Bearer ','');
            let secret = process.env["SIGN_KEY"];
            let jwtDecoded = jwt.verify(token, secret, (error, decoded) => {
                if(error) throw new Error(error);
                return decoded;
            });
            userInfo.params.id = jwtDecoded.data.id;
            delete userInfo.params.type;
        };
        userInfo.raw = false; //是否开启原生查询
        userInfo.include = [ // 执行预先加载
            { model: Roles },
            { model: Article },
            { model: Comments },
            // { model: Danmu }
        ];
        DAO.findOne(Users, userInfo, data => {
            let userData = data.data;
            let userRoles = toolsUtil.montageStr(userData.roles, 'id');
            let roleInfo = {
                params: {
                    id: userRoles
                },
                include:[
                    {model: Menus},
                ]
            };
            DAO.findOne(Roles, roleInfo, roleData => {
                let roleMenus = roleData.data.menus;
                // 找出按钮类型
                let buttonList = roleMenus.filter(item => item.type == MENUS_TYPE.BUTTON.value)
                // 筛查出权限
                let perms = toolsUtil.montageStr(buttonList, 'perms');
                userData.dataValues.perms = perms;
                // 头像地址拼接
                // userData.dataValues.avatar = baseURL+userData.dataValues.avatar;
                res.sendResultAto(userData, 200, '查询成功');
            })
        });
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

// 删除用户
exports.delete = (req, res) => {
    try {
        const userInfo = req.body;
        usersRoles.destroy({ where:{ userId:userInfo.id } })
        .then(data => {
            DAO.delete(Users, { id:userInfo.id }, data => {
                res.sendResult(data);
            });
        })
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};

// 删除所有用户
exports.deleteAll = (req, res) => {
    try {
        DAO.deleteAll(Users, data => {
            res.sendResult(data);
        });
    } catch (e) {
        console.log(e);
        logger.error(e);
        res.sendResultAto(null, 500, '服务器错误');
    };
};
